/*
 *  Copyright 2012 yura.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */

/*
 * EditTemplateScrean.java
 *
 * Created on 10.06.2012, 13:11:53
 */

package org.opu.odg.m_ui;

import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.opu.odg.dg.DocumentGeneraionService;
import org.opu.odg.dg.incomingdata.ContentDescription;
import org.opu.odg.dg.incomingdata.ContextIteration;
import org.opu.odg.dg.incomingdata.CustomContentDescription;
import org.opu.odg.dg.incomingdata.DatabaseContentDescription;
import org.opu.odg.dg.logicbeans.ArchiveFileTemplateForDG;
import org.opu.odg.dg.logicbeans.ArchiveFileTemplateForDG.ChangeableEntryDeterminator;
import org.opu.odg.dg.logicbeans.ArchiveFileTemplateForDG.DirectFileNamesEntryDeterminator;
import org.opu.odg.dg.logicbeans.ArchiveFileTemplateForDG.XpathEntryDeterminator;
import org.opu.odg.dg.logicbeans.SingleFileTemplateForDG;
import org.opu.odg.dg.logicbeans.Template;
import org.opu.odg.dg.logicbeans.TemplateFile;
import org.opu.odg.dg.logicbeans.TemplateMetaInf;
import org.opu.odg.dg.logicbeans.TemplateMetaInf.Type;
import org.opu.odg.dg.question.CustomContentQuestion;
import org.opu.odg.dg.question.QuestionsForDocGeneration;
import org.opu.odg.dg.question.QuestionsScreen;
import org.opu.odg.dg.question.TextQuestion;
import org.opu.odg.dg.xml.ContentMapping.ContentEntry;
import org.opu.odg.m_ui.beans.AbstractBean;
import org.opu.odg.m_ui.beans.ContentBean;
import org.opu.odg.m_ui.beans.ContentBean.ContentType;
import org.opu.odg.m_ui.beans.VariableBean;
import org.opu.odg.m_ui.tmp.TemplateRepositoryImpl;
import org.opu.odg.m_ui.util.LinkedHashtable;
import org.opu.odg.dg.util.ObjectHolder;
import org.opu.odg.m_ui.util.UIUtil;

/**
 *
 * @author yura
 */
public class EditTemplateScrean extends javax.swing.JDialog implements VarChangesListener {
    private ResourceBundle bundle = ResourceBundle.getBundle("org.opu.odg.m_ui.Bundle");
    private DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode("root");

    private byte[] templateInside;
    private Template editingTemplate;
    private List<ContentBean> contentBeans;

    private DocumentGeneraionService generaionService;
    private TemplateRepositoryImpl templateRepository;
    
    private boolean editing = false;

    /** Creates new form EditTemplateScrean */
    public EditTemplateScrean(DocumentGeneraionService generaionService,
            TemplateRepositoryImpl templateRepository, Frame parent) {
        super(parent, true);
        this.generaionService = generaionService;
        this.templateRepository = templateRepository;
        initComponents();
        setLocationRelativeTo(null);
        hideAll();
        pack();

        templateContentTree.setCellRenderer(new TreeCellRendererImpl());
        templateContentTree.addTreeSelectionListener(new TreeSelectionListener() {

            public void valueChanged(TreeSelectionEvent e) {
                enableContentBtn();
            }
        });

        templateContentTree.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() >=2
                        && editConentBtn.isEnabled()) {
                    editConentBtnActionPerformed(null);
                } else if (e.getButton() == MouseEvent.BUTTON2) {
                    // context menu
                }
            }

        });
    }

    public void setEditingTemplate(Template editingTemplate, String name) 
            throws IOException {
        try {
            editing = true;
            this.editingTemplate = editingTemplate;
            if (editingTemplate != null) {
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                editingTemplate.getTemplateFile().store(bout);
                templateInside = bout.toByteArray();
                nameFiled.setText(name);

                // TODO {
                billetList.setSelectedIndex(3);
                // }
                final TemplateMetaInf metaInf = editingTemplate.getMetaInf();
                if (metaInf != null) {
                    final Type type = metaInf.getType();
                    fileType.setSelectedIndex(type == Type.SingleFile ? 0 : 1);
                    if (type == Type.ArchiveFile) {
                        ChangeableEntryDeterminator ed = metaInf.getEntryDeterminator();
                        if (ed != null) {
                            entryDetermTextAr.setText(ed.toPlaineText());
                            entryModelsList.setSelectedIndex(ed instanceof 
                                    DirectFileNamesEntryDeterminator ? 0 : 1);
                        }
                    }
                }
            
                reset();

                if (metaInf != null) {
                    Map<String, ContentDescription> contents = metaInf.getContents();
                    for (ContentBean contentBean : contentBeans) {
                        String contentName = contentBean.getName();
                        if (contents.containsKey(contentName)) {
                            contentBean.setDescribesExternalTag(contents.get(
                                    contentName).isDescribesExternalTag());
                        }
                    }
                }
            
                QuestionsForDocGeneration questions = editingTemplate.getTemplateQuestions();
                if (questions != null) {
                    List<String> globalVarList = questions.getGlobalVarList();
                    for (ContentBean contentBean : contentBeans) {
                        for (VariableBean variableBean : new ArrayList<VariableBean>(
                                contentBean.getVariables())) {
                            if (globalVarList.contains(variableBean.getName())) {
                                globalVarList.remove(variableBean.getName());
                                variableBean.setCurrentContent(null);
                                applyVarChanges(contentBean, variableBean);
                            }
                        }
                    }

                    List<VariableBean> list = getListInRootNode(0);
                    for (VariableBean variableBean : list) {
                        if (globalVarList.contains(variableBean.getName())) {
                            globalVarList.remove(variableBean.getName());
                        }
                    }

                    for (String string : globalVarList) {
                        applyVarChanges(null, new VariableBean(string, null, null));
                    }
                }
                
            } else {
                templateInside = null;
            }
            fileNameField.setText("");
        } finally {
            editing = false;
        }
    }

    @Override
    public void onContentChanged(ContentBean content) {
        templateContentTree.repaint();
        enableSaveBtn();
    }

    @Override
    public void applyVarChanges(ContentBean previousContent, VariableBean variable) {
        ContentBean currentContent = variable.getCurrentContent();
        if ((previousContent == null && currentContent == null)||
                (previousContent != null && previousContent.equals(currentContent))) {
            // it's means that content does not changed
            return ;
        }

        LinkedHashtable hashtable = new LinkedHashtable();
        LinkedHashtable globalVarHashtable = new LinkedHashtable();
        hashtable.put(bundle.getString("global_variables"), globalVarHashtable);
        LinkedHashtable contentsHashtable = new LinkedHashtable();
        hashtable.put(bundle.getString("contents"), contentsHashtable);

        List<VariableBean> currentGlobalVars = getListInRootNode(0);

        if (currentContent == null) {
            removeVariable(previousContent.getVariables().iterator(), variable);
            currentGlobalVars.add(variable);
        } else {
            if (previousContent != null) {
                removeVariable(previousContent.getVariables().iterator(), variable);
            } else {
                removeVariable(currentGlobalVars.iterator(), variable);
            }
            currentContent.getVariables().add(variable);
        }

        for (VariableBean variableBean : currentGlobalVars) {
            globalVarHashtable.put(variableBean, "");
        }

        for (Object contentBean : getListInRootNode(1)) {
            pushContentToHashTable(contentsHashtable, (ContentBean) contentBean);
        }

        resetResultTreeData(hashtable);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        topPanel = new javax.swing.JPanel();
        templateNameLbl = new javax.swing.JLabel();
        nameFiled = new javax.swing.JTextField();
        existingBilletLbl = new javax.swing.JLabel();
        billetList = new javax.swing.JComboBox();
        centerPanel = new javax.swing.JPanel();
        fileTypeLbl = new javax.swing.JLabel();
        fileType = new javax.swing.JComboBox();
        entryModeLbl = new javax.swing.JLabel();
        entryModelsList = new javax.swing.JComboBox();
        entryDetermScrollPane = new javax.swing.JScrollPane();
        entryDetermTextAr = new javax.swing.JTextArea();
        templateContentPanel = new javax.swing.JPanel();
        templateContentScrollPan = new javax.swing.JScrollPane();
        templateContentTree = new javax.swing.JTree(rootTreeNode, true);
        editConentBtn = new javax.swing.JButton();
        bottomPanel = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();
        fileLbl = new javax.swing.JLabel();
        fileNameField = new javax.swing.JTextField();
        openFileBtn = new javax.swing.JButton();
        jPanel3 = new javax.swing.JPanel();
        cancelBtn = new javax.swing.JButton();
        saveBtn = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        setTitle(bundle.getString("template.new.title")); // NOI18N

        templateNameLbl.setText(bundle.getString("template.new.name")); // NOI18N

        existingBilletLbl.setText(bundle.getString("template.new.billet")); // NOI18N

        billetList.setModel(new javax.swing.DefaultComboBoxModel(new String[] { bundle.getString("billetList.docx"), bundle.getString("billetList.odt"), bundle.getString("billetList.xml"), bundle.getString("billetList.custom")}));
        billetList.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                billetListActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout topPanelLayout = new javax.swing.GroupLayout(topPanel);
        topPanel.setLayout(topPanelLayout);
        topPanelLayout.setHorizontalGroup(
            topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(topPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(templateNameLbl)
                    .addComponent(existingBilletLbl))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(billetList, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(nameFiled, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE))
                .addContainerGap(79, Short.MAX_VALUE))
        );
        topPanelLayout.setVerticalGroup(
            topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(topPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(templateNameLbl)
                    .addComponent(nameFiled, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(topPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(existingBilletLbl)
                    .addComponent(billetList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(43, Short.MAX_VALUE))
        );

        getContentPane().add(topPanel, java.awt.BorderLayout.PAGE_START);

        fileTypeLbl.setText(bundle.getString("template.new.type")); // NOI18N

        fileType.setModel(new javax.swing.DefaultComboBoxModel(new String[] {bundle.getString("fileType.single"), bundle.getString("fileType.archive")}));
        fileType.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileTypeActionPerformed(evt);
            }
        });

        entryModeLbl.setText(bundle.getString("template.new.entryDeterminationModel")); // NOI18N

        entryModelsList.setModel(new javax.swing.DefaultComboBoxModel(new String[] {bundle.getString("entryModels.fname"), bundle.getString("entryModels.xpath")}));
        entryModelsList.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                entryModelsListActionPerformed(evt);
            }
        });

        entryDetermScrollPane.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("template.new.entryDeterminator"))); // NOI18N

        entryDetermTextAr.setColumns(20);
        entryDetermTextAr.setRows(5);
        entryDetermScrollPane.setViewportView(entryDetermTextAr);

        templateContentScrollPan.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("template.new.content"))); // NOI18N
        templateContentScrollPan.setForeground(new java.awt.Color(254, 254, 254));

        templateContentTree.setRootVisible(false);
        templateContentScrollPan.setViewportView(templateContentTree);

        editConentBtn.setText(bundle.getString("template.new.edit")); // NOI18N
        editConentBtn.setToolTipText(bundle.getString("template.new.edit")); // NOI18N
        editConentBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editConentBtnActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout templateContentPanelLayout = new javax.swing.GroupLayout(templateContentPanel);
        templateContentPanel.setLayout(templateContentPanelLayout);
        templateContentPanelLayout.setHorizontalGroup(
            templateContentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, templateContentPanelLayout.createSequentialGroup()
                .addComponent(templateContentScrollPan, javax.swing.GroupLayout.DEFAULT_SIZE, 429, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(editConentBtn, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        templateContentPanelLayout.setVerticalGroup(
            templateContentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(templateContentPanelLayout.createSequentialGroup()
                .addGroup(templateContentPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(templateContentPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(templateContentScrollPan, javax.swing.GroupLayout.DEFAULT_SIZE, 180, Short.MAX_VALUE))
                    .addGroup(templateContentPanelLayout.createSequentialGroup()
                        .addGap(64, 64, 64)
                        .addComponent(editConentBtn)))
                .addContainerGap())
        );

        javax.swing.GroupLayout centerPanelLayout = new javax.swing.GroupLayout(centerPanel);
        centerPanel.setLayout(centerPanelLayout);
        centerPanelLayout.setHorizontalGroup(
            centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(centerPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(templateContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(centerPanelLayout.createSequentialGroup()
                        .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(centerPanelLayout.createSequentialGroup()
                                .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                    .addComponent(entryModeLbl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(fileTypeLbl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                                .addGap(41, 41, 41)
                                .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                    .addComponent(fileType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                    .addComponent(entryModelsList, 0, 328, Short.MAX_VALUE))
                                .addGap(0, 61, Short.MAX_VALUE))
                            .addComponent(entryDetermScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 507, Short.MAX_VALUE))
                        .addContainerGap())))
        );
        centerPanelLayout.setVerticalGroup(
            centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(centerPanelLayout.createSequentialGroup()
                .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(fileTypeLbl)
                    .addComponent(fileType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(centerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(entryModeLbl)
                    .addComponent(entryModelsList, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(entryDetermScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(templateContentPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addContainerGap())
        );

        getContentPane().add(centerPanel, java.awt.BorderLayout.CENTER);

        bottomPanel.setLayout(new java.awt.BorderLayout());

        jPanel2.setPreferredSize(new java.awt.Dimension(528, 48));

        fileLbl.setText(bundle.getString("template.new.file")); // NOI18N

        fileNameField.setEditable(false);

        openFileBtn.setText(bundle.getString("template.new.open")); // NOI18N
        openFileBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openFileBtnActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(fileLbl)
                .addGap(97, 97, 97)
                .addComponent(fileNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)
                .addGap(18, 18, 18)
                .addComponent(openFileBtn)
                .addGap(68, 68, 68))
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(fileLbl)
                    .addComponent(fileNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(openFileBtn))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        bottomPanel.add(jPanel2, java.awt.BorderLayout.CENTER);

        cancelBtn.setText(bundle.getString("cancel")); // NOI18N
        cancelBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelBtnActionPerformed(evt);
            }
        });
        jPanel3.add(cancelBtn);

        saveBtn.setText(bundle.getString("Save")); // NOI18N
        saveBtn.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveBtnActionPerformed(evt);
            }
        });
        jPanel3.add(saveBtn);

        bottomPanel.add(jPanel3, java.awt.BorderLayout.PAGE_END);

        getContentPane().add(bottomPanel, java.awt.BorderLayout.PAGE_END);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void openFileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openFileBtnActionPerformed
        JFileChooser fch = new JFileChooser();
        fch.setDialogType(JFileChooser.OPEN_DIALOG);
        fch.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int returnVal = fch.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fch.getSelectedFile();
            FileInputStream is = null;
            try {
                is = new FileInputStream(file);
                templateInside = IOUtils.toByteArray(is);
                fileNameField.setText(file.getAbsolutePath());
            } catch (Exception ex) {
                ex.printStackTrace(System.out);
                JOptionPane.showMessageDialog(this, ex);
            } finally {
                IOUtils.closeQuietly(is);
                reset();
            }
            if (!fileNameField.getText().isEmpty()) {
                nameFiled.setText(FilenameUtils.getBaseName(file.getName()));
            }
        }
    }//GEN-LAST:event_openFileBtnActionPerformed

    private void billetListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_billetListActionPerformed
        if (!editing) {
            reset();
        }
    }//GEN-LAST:event_billetListActionPerformed

    private void cancelBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelBtnActionPerformed
        dispose();
    }//GEN-LAST:event_cancelBtnActionPerformed

    private void entryModelsListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_entryModelsListActionPerformed
        if (!editing) {
            reset();
        }
}//GEN-LAST:event_entryModelsListActionPerformed

    private void fileTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileTypeActionPerformed
        if (!editing) {
            reset();
        }
}//GEN-LAST:event_fileTypeActionPerformed

    private void editConentBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editConentBtnActionPerformed
        Object object = getCurrentObjectInResultTree();
        if (object != null) {
            if (object instanceof VariableBean) {
                new VarEditScrean(null, true, (VariableBean) object, this).setVisible(true);
            } else if (object instanceof ContentBean) {
                new ContentEditScrean(null, true, this, (ContentBean) object).setVisible(true);
            }
        }
    }//GEN-LAST:event_editConentBtnActionPerformed

    private void saveBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed
        try {
            if (editingTemplate == null) {
                throw new NullPointerException("Editing template is null");
            }

            if (contentBeans == null) {
                throw new NullPointerException("Contents was not initialized");
            }

            TemplateMetaInf metaInf = editingTemplate.getMetaInf();
            if (metaInf == null) {
                throw new NullPointerException("Metadata for editing template wasn't created");
            }
            
            QuestionsForDocGeneration questions = new QuestionsForDocGeneration();
            QuestionsScreen questionsScreen = new QuestionsScreen();
            questions.addQuestionsScreen(questionsScreen);

            List<VariableBean> globalVars = getListInRootNode(0);
            for (VariableBean var : globalVars) {
                questionsScreen.addQuestion(new TextQuestion(var.getName(), ""));
            }

            Map<String, ContentDescription> contents = metaInf.getContents();

            for (ContentBean content : contentBeans) {
                contents.put(content.getName(), convertBeanToDescription(content));
                if (content.getContentType() == ContentType.Custom) {
                    questionsScreen.addQuestion(new CustomContentQuestion(content.getName(), ""));
                }
            }

            editingTemplate.setTemplateQuestions(questions);

            templateRepository.saveOrUpdate(editingTemplate, nameFiled.getText());

            dispose();
        } catch(Exception ex) {
            showError(ex);
        }

        
    }//GEN-LAST:event_saveBtnActionPerformed

    private Template createTemplate(byte[] binaryData) throws Exception {
        Template template = new Template();
        template.setId(getCurrentTemplateId());
        ObjectHolder<TemplateFile> holder = new ObjectHolder<TemplateFile>();
        template.setTemplateMetaInf(getTemplateMetaInf(holder));
        TemplateFile object = holder.getObject();
        object.load(new ByteArrayInputStream(binaryData));
        template.setTemplateFile(object);

        return template;
    }

    private void reset() {
        hideAll();
        if (templateInside != null) {
            // set content settings
            try {
                if (!editing) {
                    editingTemplate = createTemplate(templateInside);
                }

                List<ContentEntry> mappedEntry = new ArrayList<ContentEntry>();
                List<String> globalVars = new ArrayList<String>();
                generaionService.validate(editingTemplate, globalVars, mappedEntry);

                templateContentPanel.setVisible(true);
                templateContentScrollPan.setVisible(true);
                templateContentTree.setVisible(true);
                editConentBtn.setVisible(true);
                resetResultTreeData(createHashTable(mappedEntry, globalVars));
                enableSaveBtn();
            } catch (Exception ex) {
                templateInside = null;
                editingTemplate = null;
                fileNameField.setText("");
                showError(ex);
            }
        }

        if (billetList.getSelectedIndex() == 3) {
            // it's custom file
            fileTypeLbl.setVisible(true);
            fileType.setVisible(true);

            if (fileType.getSelectedIndex() == 1) {
                // it's custom archive
                entryModeLbl.setVisible(true);
                entryDetermScrollPane.setVisible(true);
                entryDetermTextAr.setVisible(true);
                entryModelsList.setVisible(true);
            }
        }

        topPanel.revalidate();
        templateContentPanel.revalidate();
        centerPanel.revalidate();
        bottomPanel.revalidate();
        pack();
    }

    // <editor-fold defaultstate="collapsed" desc="hide all extandable component">
    private void hideAll() {
        templateContentPanel.setVisible(false);
        fileTypeLbl.setVisible(false);
        entryDetermScrollPane.setVisible(false);
        entryDetermTextAr.setVisible(false);
        fileType.setVisible(false);
        entryModeLbl.setVisible(false);
        entryModelsList.setVisible(false);
        templateContentScrollPan.setVisible(false);
        templateContentTree.setVisible(false);
        editConentBtn.setVisible(false);
        editConentBtn.setEnabled(false);
        saveBtn.setEnabled(false);
    }// </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="create template MetaInf">
    private TemplateMetaInf getTemplateMetaInf(ObjectHolder<TemplateFile> tfg) {
        //"Docx", "Odt", "Xml", "Custom"
        switch (billetList.getSelectedIndex()) {
            case 0:
                return setMetaInfToTemplate(TemplateMetaInf.getDocxBillet(), tfg);
            case 1:
                return setMetaInfToTemplate(TemplateMetaInf.getOdtBillet(), tfg);
            case 2:
                tfg.setObject(new SingleFileTemplateForDG());
                return TemplateMetaInf.getXmlBillet();
            case 3:
                Type fTp = fileType.getSelectedIndex() == 0 ? TemplateMetaInf
                        .Type.SingleFile : TemplateMetaInf.Type.ArchiveFile;
                ChangeableEntryDeterminator ced = null;
                if (fTp == TemplateMetaInf.Type.ArchiveFile) {
                    String[] split = entryDetermTextAr.getText().split("\\r?\\n");
                    //"File names in archive", "Xpath expressions to get file names"
                    if (entryModelsList.getSelectedIndex() == 0) {
                        if (split == null || split.length < 1) {
                            exception("Entry determination expect 1 row (at least).");
                        }
                        ced = new DirectFileNamesEntryDeterminator(Arrays.asList(split));
                    } else {
                        if (split == null || split.length < 2) {
                            exception("Entry determination expect 2 row (at least)");
                        }
                        String[] s = new String[split.length - 1];
                        System.arraycopy(split, 1, s, 0, s.length);
                        ced = new XpathEntryDeterminator(split[0], Arrays.asList(s));
                    }
                } else {
                    tfg.setObject(new SingleFileTemplateForDG());
                }

                TemplateMetaInf mi = new TemplateMetaInf(fTp, ced, null);

                if (fTp == TemplateMetaInf.Type.ArchiveFile) {
                    tfg.setObject(new ArchiveFileTemplateForDG(ced));
                }

                return mi;
            default:
                throw new IllegalArgumentException("billetList#getSelectedIndex");
        }
    }// </editor-fold>

    private LinkedHashtable createHashTable(List<ContentEntry> mappedEntry,
            List<String> globalVars) throws IOException {
        LinkedHashtable hashtable = new LinkedHashtable();
        LinkedHashtable globalVarHashtable = new LinkedHashtable();
        if (globalVars != null && !globalVars.isEmpty()) {
            for (String string : globalVars) {
                globalVarHashtable.put(new VariableBean(string, null, null), "");
            }
        }
        hashtable.put(bundle.getString("global_variables"), globalVarHashtable);

        LinkedHashtable contentsHashtable = new LinkedHashtable();
        if (mappedEntry != null && !mappedEntry.isEmpty()) {
            for (ContentEntry contentEntry : mappedEntry) {
                pushContentToHashTable(contentsHashtable, toContentBean(contentEntry));
            }
        }
        hashtable.put(bundle.getString("contents"), contentsHashtable);

        return hashtable;
    }

    private void resetResultTreeData(LinkedHashtable hashtable) {
        rootTreeNode.removeAllChildren();
        JTree.DynamicUtilTreeNode.createChildren(rootTreeNode, hashtable);
        templateContentTree.setModel(new DefaultTreeModel(rootTreeNode));
        enableContentBtn();

        getContents(contentBeans = new ArrayList<ContentBean>(), getListInRootNode(1));

        UIUtil.expandAll(templateContentTree, true);
    }

    private void getContents(List<ContentBean> holder, Collection<ContentBean> contents) {
        for (ContentBean content : contents) {
            holder.add(content);
            getContents(holder, content.getChildrens());
        }
    }

    private List getListInRootNode(int node) {
        List list = new ArrayList();
        DefaultMutableTreeNode vars = (DefaultMutableTreeNode)rootTreeNode.getChildAt(node);
        for(int i = 0; i < vars.getChildCount(); i++) {
            DefaultMutableTreeNode var = (DefaultMutableTreeNode)vars.getChildAt(i);
            list.add(var.getUserObject());
        }
        return list;
    }

    private void removeVariable(Iterator<VariableBean> it, VariableBean variable) {
        while (it.hasNext()) {
            if (variable.equals(it.next())) {
                it.remove();
                return;
            }
        }
//        throw new IllegalArgumentException();
    }

    private ContentBean toContentBean(ContentEntry contentEntry) throws IOException {
        String name = contentEntry.name;
        ContentBean contentBean = new ContentBean();
        contentBean.setName(name);

        if (editingTemplate != null && editingTemplate.getMetaInf() != null &&
                editingTemplate.getMetaInf().getContents().containsKey(name)) {
            ContentDescription get = editingTemplate.getMetaInf().getContents().get(name);
            if (get instanceof DatabaseContentDescription) {
                contentBean.setContentType(ContentType.Database);
                contentBean.setQuery(((DatabaseContentDescription)get).getQuery());
                contentBean.setDatabaseSettings(((DatabaseContentDescription)get).getDatabaseSettings());
            } else {
                contentBean.setContentType(ContentType.Custom);
            }
            contentBean.setConfigured(true);
        }

        if (contentEntry.subContents != null && !contentEntry.subContents.isEmpty()) {
            for (ContentEntry subContentEntry : contentEntry.subContents) {
                contentBean.addChildren(toContentBean(subContentEntry));
            }
        }

        if (contentEntry.varNameList != null && !contentEntry.varNameList.isEmpty()) {
            for (String string : contentEntry.varNameList) {
                VariableBean var = new VariableBean(string, contentBean, contentBean);
                contentBean.addVariable(var);
            }
        }

        return contentBean;
    }

    private void pushContentToHashTable(LinkedHashtable hashtable, ContentBean contentEntry) {
        LinkedHashtable subHashtable = new LinkedHashtable();

        if (!contentEntry.getVariables().isEmpty()) {
            LinkedHashtable subVarHashtable = new LinkedHashtable();
            for (VariableBean var : contentEntry.getVariables()) {
                subVarHashtable.put(var, "");
            }
            subHashtable.put(bundle.getString("content_variables"), subVarHashtable);
        }

        if (!contentEntry.getChildrens().isEmpty()) {
            LinkedHashtable subContentHashtable = new LinkedHashtable();
            for (ContentBean subContentEntry : contentEntry.getChildrens()) {
                pushContentToHashTable(subContentHashtable, subContentEntry);
            }
            subHashtable.put(bundle.getString("child_contents"), subContentHashtable);
        }

        hashtable.put(contentEntry, !subHashtable.isEmpty() ? subHashtable : "");
    }

    private void enableContentBtn() {
        Object nodeInfo = getCurrentObjectInResultTree();
        editConentBtn.setEnabled(nodeInfo != null && nodeInfo instanceof AbstractBean);
    }

    private Object getCurrentObjectInResultTree() {
        DefaultMutableTreeNode node = (DefaultMutableTreeNode)
                templateContentTree.getLastSelectedPathComponent();
        if (node == null) {
            return null;
        }
        return node.getUserObject();
    }

    private TemplateMetaInf setMetaInfToTemplate(TemplateMetaInf mi, ObjectHolder<TemplateFile> tfg) {
        tfg.setObject(new ArchiveFileTemplateForDG(mi.getEntryDeterminator()));
        return mi;
    }

    private void enableSaveBtn() {
        for (ContentBean contentBean : contentBeans) {
            if (!contentBean.isConfigured()) {
                saveBtn.setEnabled(false);
                return;
            }
        }
        saveBtn.setEnabled(true);
    }

    private ContentDescription convertBeanToDescription(ContentBean bean) {
        List<VariableBean> variables = new ArrayList<VariableBean>(bean.getVariables());
        for (Iterator<VariableBean> it = variables.iterator(); it.hasNext();) {
            if (ContextIteration.ITERATION.equals(it.next().getName())) {
                it.remove();
            }
        }
        String header[] = new String[variables.size()];
        for (int i = 0; i < header.length; i++) {
            header[i] = variables.get(i).getName();
        }

        ContentDescription description;
        switch (bean.getContentType()) {
            case Custom:
                description = new CustomContentDescription(header, null);
                break;
            case Database:
                if (bean.getQuery() == null) {
                    throw new IllegalArgumentException("Query for "
                            + bean.getName() + " is not setted.");
                }
                description = new DatabaseContentDescription(
                        bean.getDatabaseSettings(), bean.getQuery());
                break;
            default:
                throw new IllegalArgumentException("Unsupported content type"
                        + bean.getContentType());
        }

        description.setDescribesExternalTag(bean.isDescribesExternalTag());

        return description;
    }
    
    private Integer getCurrentTemplateId() {
        return editingTemplate != null ? editingTemplate.getId() : null;
    }

    private void exception(String str) {
        throw new IllegalArgumentException(str);
    }

    protected void showError(Exception ex) throws HeadlessException {
        ex.printStackTrace(System.out);
        UIUtil.niceEx(ex, getTitle(), "");
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    /** Combo box that store type of teplate: docx, odt, ...*/
    private javax.swing.JComboBox billetList;
    private javax.swing.JPanel bottomPanel;
    private javax.swing.JButton cancelBtn;
    private javax.swing.JPanel centerPanel;
    private javax.swing.JButton editConentBtn;
    private javax.swing.JScrollPane entryDetermScrollPane;
    private javax.swing.JTextArea entryDetermTextAr;
    private javax.swing.JLabel entryModeLbl;
    private javax.swing.JComboBox entryModelsList;
    private javax.swing.JLabel existingBilletLbl;
    private javax.swing.JLabel fileLbl;
    private javax.swing.JTextField fileNameField;
    private javax.swing.JComboBox fileType;
    private javax.swing.JLabel fileTypeLbl;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JTextField nameFiled;
    private javax.swing.JButton openFileBtn;
    private javax.swing.JButton saveBtn;
    private javax.swing.JPanel templateContentPanel;
    private javax.swing.JScrollPane templateContentScrollPan;
    private javax.swing.JTree templateContentTree;
    private javax.swing.JLabel templateNameLbl;
    private javax.swing.JPanel topPanel;
    // End of variables declaration//GEN-END:variables

}

